﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using ShowDependencies.Properties;

namespace ShowDependencies
{
	public partial class frmShowDependencies : Form
	{
		#region Fields (6) 

		private AuthoritExtensibility.AuthoritEventArgs eventArgs;
		private StringCollection gridColumnHeaders;
		private StringCollection gridColumnNames;
		private Stack<Cursor> myCursors = new Stack<Cursor>();
		private List<TreeNode> treeNodes;
		private ObjectSummaryCollection uniqueObjects;
		private System.DateTime startTime;
		private System.DateTime endTime;

		#endregion Fields 

		private PluginManager plugin;

		public PluginManager Plugin
		{
			get { return plugin; }
			set { plugin = value; }
		}

		#region Constructors (1) 

		/// <summary>
		/// Initializes a new instance of the <see cref="frmShowDependencies"/> class
		/// </summary>
		public frmShowDependencies()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="frmShowDependencies"/> class
		/// </summary>
		/// <param name="pluginManager">Instance of the <see cref="PluginManager"/> class that owns this <see cref="frmShowDependencies"/></param>
		public frmShowDependencies(PluginManager pluginManager) : this()
		{
			this.plugin = pluginManager;
		}

		#endregion Constructors 

		#region Properties (3) 

		public AuthoritExtensibility.AuthoritEventArgs EventArgs
		{
			get { return eventArgs; }
			set { eventArgs = value; }
		}

		public System.DateTime StartTime
		{
			get { return startTime; }
			set { startTime = value; }
		}

		public System.DateTime EndTime
		{
			get { return endTime; }
			set { endTime = value; }
		}

		public List<TreeNode> TreeNodes
		{
			get { return treeNodes; }
			set { treeNodes = value; }
		}

		public ObjectSummaryCollection UniqueObjects
		{
			get { return uniqueObjects; }
			set { uniqueObjects = value; }
		}

		#endregion Properties 

		#region Methods (17) 

		// Private Methods (17) 

		private void AllDependencies_Load(object sender, EventArgs e)
		{
			CursorWait();
			SetProperties();
			this.treeObjectsUsed.BeginUpdate();
			this.treeObjectsUsed.Nodes.Clear();
			this.treeObjectsUsed.Nodes.AddRange(treeNodes.ToArray());
			this.treeObjectsUsed.EndUpdate();
			this.lblTotalObjects.Text = String.Format(CultureInfo.CurrentCulture, Properties.Resources.LabelTotalTreeNodesText, treeObjectsUsed.GetNodeCount(true));
			CursorRestore();
		}

		private void btnCollapseAll_Click(object sender, EventArgs e)
		{
			CursorWait();
			treeObjectsUsed.BeginUpdate();
			treeObjectsUsed.CollapseAll();
			treeObjectsUsed.EndUpdate();
			CursorRestore();
		}

		private void btnExpandAll_Click(object sender, EventArgs e)
		{
			CursorWait();
			treeObjectsUsed.BeginUpdate();
			treeObjectsUsed.ExpandAll();
			treeObjectsUsed.EndUpdate();
			CursorRestore();
		}

		private void btnSelectAll_Click(object sender, EventArgs e)
		{
			CursorWait();
			foreach (DataGridViewRow row in dgvUniqueObjects.Rows)
			{
				row.Selected = true;
			}
			CursorRestore();
		}

		private void btnSelectNone_Click(object sender, EventArgs e)
		{
			CursorWait();
			foreach (DataGridViewRow row in dgvUniqueObjects.SelectedRows)
			{
				row.Selected = false;
			}
			CursorRestore();
		}

		private void CheckNodes(TreeNodeCollection nodes, bool selected)
		{
			foreach (TreeNode node in nodes)
			{
				node.Checked = selected;
				if (node.GetNodeCount(false) > 0)
				{
					CheckNodes(node.Nodes, selected);
				}
			}
		}

		private void CursorRestore()
		{
			this.Cursor = this.myCursors.Pop();
		}

		private void CursorWait()
		{
			this.myCursors.Push(this.Cursor);
			this.Cursor = Cursors.WaitCursor;
		}

		private void GetGridViewValues()
		{
			if (Settings.Default.GridColumnHeaders.Count == 0)
			{
				MessageBox.Show(Resources.GridColumnHeadersErrorMessage,Resources.GridColumnErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
				this.Close();
			}
			if (Settings.Default.GridColumnNames.Count == 0)
			{
				MessageBox.Show(Resources.GridColumnNamesErrorMessage, Resources.GridColumnErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
				this.Close();
			}
			if (Settings.Default.GridColumnHeaders.Count != Settings.Default.GridColumnNames.Count)
			{
				MessageBox.Show(Resources.GridColumnMismatchErrorMessage, Resources.GridColumnErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
				this.Close();
			}
			this.gridColumnNames = Settings.Default.GridColumnNames;
			this.gridColumnHeaders = Settings.Default.GridColumnHeaders;
		}

		private string GetVersionString()
		{
			Version v = Assembly.GetExecutingAssembly().GetName().Version;
			string version = string.Format(CultureInfo.InvariantCulture, "v{0}.{1}.{2}.{3}", v.Major, v.Minor, v.Build, v.Revision);
			return version;
		}

		private void LoadDataGrid()
		{
			dgvUniqueObjects.AutoGenerateColumns = true;
			dgvUniqueObjects.MultiSelect = true;
			for (int columnNameIndex = 0; columnNameIndex < gridColumnNames.Count; columnNameIndex++)
			{
				dgvUniqueObjects.Columns.Add(gridColumnNames[columnNameIndex], gridColumnHeaders[columnNameIndex]);
			}
			HashSet<int> errorValues = new HashSet<int>();
			for (int objectIndex = 0; objectIndex < uniqueObjects.Count; objectIndex++)
			{
				Type objSummaryType = uniqueObjects.GetItemByIndex(objectIndex).GetType();
				List<string> propValues = new List<string>();
				for (int columnIndex = 0; columnIndex < gridColumnNames.Count; columnIndex++)
				{
					try
					{
						propValues.Add(objSummaryType.GetProperty(gridColumnNames[columnIndex]).GetValue(uniqueObjects.GetItemByIndex(objectIndex), null).ToString());
					}
					catch (Exception e)
					{
						errorValues.Add(columnIndex);
					}
				}
				dgvUniqueObjects.Rows.Add(propValues.ToArray<string>());
			}
			if (errorValues.Count > 0)
			{
				StringBuilder sb = new StringBuilder();
				sb.AppendLine(Resources.ExceptionPropertyAddDialogMessage);
				foreach (int propValIndex in errorValues)
				{
					sb.AppendLine(gridColumnNames[propValIndex]);
				}
				MessageBox.Show(sb.ToString(), Resources.ExceptionPropertyAddDialogTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void LoadImageList()
		{
			imageList1.Images.Add("Book", Properties.Resources.Book);
			imageList1.Images.Add("File", Properties.Resources.File);
			imageList1.Images.Add("Glossary", Properties.Resources.Glossary);
			imageList1.Images.Add("Hyperlink", Properties.Resources.Hyperlink);
			imageList1.Images.Add("Index", Properties.Resources.Index);
			imageList1.Images.Add("IndexEntry", Properties.Resources.IndexEntry);
			imageList1.Images.Add("Macro", Properties.Resources.Macro);
			imageList1.Images.Add("Media", Properties.Resources.Media);
			imageList1.Images.Add("PublishingProfile", Properties.Resources.PublishingProfile);
			imageList1.Images.Add("Style", Properties.Resources.Style);
			imageList1.Images.Add("TableOfContents", Properties.Resources.TableOfContents);
			imageList1.Images.Add("TableOfFigures", Properties.Resources.TableOfFigures);
			imageList1.Images.Add("TitlePage", Properties.Resources.TitlePage);
			imageList1.Images.Add("Topic", Properties.Resources.Topic);            
		}

		private void menuAllNodes_Click(object sender, EventArgs e)
		{
			MessageBox.Show("Exporting the list of tree nodes is not yet implemented.", "Not Implemented", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
		}

		private void menuUniqueObjects_Click(object sender, EventArgs e)
		{
			MessageBox.Show("Exporting the list of unique objects is not yet implemented", "Not Implemented", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			
		}

		private void SetChildNodes(TreeNode currentNode, bool isChecked)
		{
			for (int i = 0; i < currentNode.Nodes.Count; i++)
			{
				currentNode.Nodes[i].Checked = isChecked;
				SetChildNodes(currentNode.Nodes[i], isChecked);
			}
		}

		private void SetProperties()
		{
			this.Text = String.Format(CultureInfo.CurrentCulture, Properties.Resources.MainFormName, GetVersionString());
			this.Icon = Resources.ShowDependenciesIcon;
			this.ShowIcon = true;
			this.btnCollapseAll.Text = Properties.Resources.ButtonCollapseAllText;
			this.btnCollapseAll.ToolTipText = Properties.Resources.ButtonCollapseAllTooltip;
			this.btnExpandAll.Text = Properties.Resources.ButtonExpandAllText;
			this.btnExpandAll.ToolTipText = Properties.Resources.ButtonExpandAllTooltip;
			this.btnSelectAll.Text = Properties.Resources.ButtonSelectAllText;
			this.btnSelectAll.ToolTipText = Properties.Resources.ButtonSelectAllTooltip;
			this.btnSelectNone.Text = Properties.Resources.ButtonSelectNoneText;
			this.btnSelectNone.ToolTipText = Properties.Resources.ButtonSelectNoneTooltip;
			this.btnViewXml.Text = Properties.Resources.ButtonViewXmlText;
			this.btnViewXml.ToolTipText = Properties.Resources.ButtonViewXmlTooltip;
			this.lblUniqueObjects.Text = String.Format(CultureInfo.CurrentCulture, Properties.Resources.LabelUniqueObjectsText, this.uniqueObjects.Count);
			this.lblUniqueObjects.ToolTipText = Properties.Resources.LabelUniqueObjectsTooltip;
			this.lblTotalObjects.ToolTipText = Properties.Resources.LabelTotalTreeNodesTooltip;
			this.lblStartTime.Text = String.Format(Resources.LabelStartTimeText, this.startTime.ToString());
			this.lblStartTime.ToolTipText = Resources.LabelStartTimeTooltip;
			this.lblEndTime.Text = String.Format(Resources.LabelEndTimeText, this.endTime.ToString());
			this.lblEndTime.ToolTipText = Resources.LabelEndTimeTooltip;
			this.lblTotalTime.Text = String.Format(Resources.LabelTotalTimeText, (this.endTime - this.startTime).Minutes, (this.endTime - this.startTime).Seconds);
			this.lblTotalTime.ToolTipText = Resources.LabelTotalTimeTooltip;
			this.gridColumnHeaders = Settings.Default.GridColumnHeaders;
			this.gridColumnNames = Settings.Default.GridColumnNames;
			LoadImageList();
			LoadDataGrid();
			this.treeObjectsUsed.ImageList = imageList1;
		}

		private void treeObjectsUsed_AfterCheck(object sender, TreeViewEventArgs e)
		{
			if (e.Node.Nodes.Count != 0)
			{
				CursorWait();
				SetChildNodes(e.Node, e.Node.Checked);
				CursorRestore();
			}
		}

		#endregion Methods 

		private void btnViewXml_Click(object sender, EventArgs e)
		{
			List<int> objectIds = dgvUniqueObjects.SelectedRows.Cast<DataGridViewRow>().Select(row => Int32.Parse(row.Cells["ObjectId"].Value.ToString())).ToList();
			string xml = this.plugin.GetXml(objectIds);
			frmViewXml xmlView = new frmViewXml(xml);
			DialogResult result = xmlView.ShowDialog(this);
		}
	}
}
